home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
007
/
life.aqm
/
life.asm
Wrap
Assembly Source File
|
1986-02-12
|
10KB
|
419 lines
;
; LIFE {from COMPUTE'S guide to machine language on the
; IBM PC, an excellent introduction to assembler.
; Ed Dablin }
;
page ,132
.sall
;
; This program plays the game of life.
; The user sets up the screen as he would like it to start
; and then presses <RETURN> and the program goes until
; he presses a key.
;
;
UP_scan equ 48h
DOWN_scan equ 50h
LEFT_scan equ 4bh
RIGHT_scan equ 4dh
SPACE_scan equ 39h
RET_scan equ 1ch
;
cell equ 15
space equ ' '
normal equ 7 ; normal attribute
;
video equ 10h ; VIDEO I/O interrupt #
DOS_func equ 21h ; DOS function call
;
locate macro row,column ; set cursor position
mov ah,2
mov dh, row
mov dl,column
mov bh,0
int video
endm
;
check macro coord,value,offset ;special macro for setup
local no_change
cmp coord,value
je no_change
add coord,offset
no_change: ret
endm
;
output macro character,attribute ; puts character on screen
mov ah,10
mov bh,0
mov cx,1
mov al,character
int video
endm
;
place macro matrix,xpos,ypos,character ; puts char in matrix
mov bx,ypos
shl bx,1
mov bx,row_addr[bx]
mov si,xpos
mov &matrix[bx+si],character
endm
;
peek macro matrix,xpos,ypos ; look into matrix
mov bx,ypos
shl bx,1
mov bx,row_addr[bx]
mov si,xpos
mov al,&matrix[bx+si]
endm
;
clear macro matrix ; clear matrix
mov cx,2000
mov al,space
lea di,es:matrix
rep stos matrix
endm
;
data segment
matrix_1 db 2000 dup (?)
matrix_2 db 2000 dup (?)
;
population dw ? ; # cells
generation dw ? ; # generations
;
row_byte equ this byte ; row counter
row_pos dw ?
col_byte equ this byte ; column counter
col_pos dw ?
;
legal_keys db UP_scan,DOWN_scan,LEFT_scan,RIGHT_scan
db SPACE_scan,RET_scan
;
key_routines dw do_up,do_down,do_left,do_right
dw era_cell,do_ret
;
; ====== Title Messages ========
title_mes dw game,cr,cr,author,cr,date,cr,cr,key_mes,0h
;
game db 'The game of LIFE.$'
cr db 13,10,'$' ; carriage ret/line feed
author db 'Implemented by Marc Sugiyama$'
date db 'September 12, 1984$'
key_mes db 'Press any key to continue:$'
ins_mes db 'Press any key to create a cell;'
db ' erase with space; start with return.$'
gen_mes db 'Generation: '
db 'Population:$'
again_mes db 'Play LIFE again (y/n)? $'
spaces db 79 dup (' '),'$'
;
row_addr dw 0 ; table of 80s to find row address
irp row,<1,2,3,4,5,6>
dw &row*80
endm
irp row,<7,8,9,10,11,12>
dw &row*80
endm
irp row,<13,14,15,16,17,18>
dw &row*80
endm
;
; offsets for 8 directions
direction dw -81,-80,-79,-1,1,79,80,81
data ends
;
stack segment stack
db 1024 dup (?)
stack ends
;
code segment
program proc far
assume es:data,ds:data,cs:code,ss:stack
push ds ; for FAR return
mov ax,0
push ax
mov ax,data
mov ds,ax
mov es,ax
call do_title ;print the title page
;
runagain: clear matrix_1 ;put spaces in matrices
clear matrix_2
mov population,0 ;zero population
mov generation,1 ;first generation
call do_setup ;set up screen
jc done ;if CF=1 then leave program
call play ;play the scenario
call again ;ask to play again
jc runagain ;if CF=1 then play again
call cls ;clear screen
;
done: ret
program endp
;
;Again asks if the player wants to play again. If so, CF
;is set. Otherwise, CF=0.
;All registers should be considered destroyed.
;
again proc near
locate 0,39 ;put cursor top line
mov dx, offset again_mes ;set DS:DX to message
call print ;print message
check_key_again:
call press_key ; get key press
and al,0dfh ;'AND' out lower case bit
cmp al,'Y'
je playagain
cmp al,'N' ;don't play again
jne check_key_again
not_again: clc ;CF=0 means return to DOS
ret
playagain: stc ;CF=1 means play again
ret
again endp
;
;Title clears the screen and prints the name of the program.
;Consider all registers destroyed.
;
do_title proc near
call cls ;clear screen
locate 1,0 ;set cursor to print message
mov si,offset title_mes ;print messages one by one
print_title: mov dx,[si] ;set DS:DX to message
cmp dx,0 ;if message offset is zero, then done
je wait_for_key
add si,2 ;point to next message
call print ;print message
jmp print_title ;get next message to print
;
wait_for_key: call press_key ;wait for key press
ret ;return to caller
do_title endp
;
;Set up the cells on the screen using user input.
;Consider all registers destroyed.
;
do_setup proc near
call cls
locate 0,0
mov dx,offset ins_mes
call print
;
mov row_pos,12 ;put cursor at center screen
mov col_pos,39
;
poscrs: locate row_byte,col_byte ;set to center of screen
mov ah,0
int 16h ;get keystroke
cmp ax,0 ;program interrupted
jne check_keys
stc ;return with error
ret
;
check_keys: mov bx,0 ;check for which key
checkloop: cmp ah,legal_keys[bx] ;if legal key, do routine
je do_key
inc bx
cmp byte ptr legal_keys[bx],0 ;last possible key?
jne checkloop
call set_cell ;possible alternative
jmp poscrs
;
do_key: shl bx,1 ;2X for word table
call key_routines[bx] ;call routine
jmp poscrs ;do next key
;
do_up: check row_pos,1,-1
do_down: check row_pos,24,1
do_left: check col_pos,0,-1
do_right: check col_pos,79,1
;put new cell down
set_cell: peek matrix_2,col_pos,row_pos ;check if cell there
cmp al,cell
je noset
output cell,normal ;if new cell,put on screen
place matrix_2,col_pos,row_pos,cell ;add to matrix
inc population
noset: ret ;return to process next key
;remove cell from matrix
era_cell: peek matrix_2,col_pos,row_pos ;check if cell there
cmp al,space
je noera
output space,normal ;put space in spot
place matrix_2,col_pos,row_pos,space ;clear matrix spot
dec population
noera: ret ;return to process next key
do_ret: pop ax
clc ;continue with main program
ret ;return to main level
do_setup endp
;
;Play, does the actual game, printing the generation at the
;top of the screen, as well as the number of cells living.
;Consider all registers destroyed.
;
play proc near
locate 0,0 ;clear frist row
mov dx,offset spaces
call print
locate 0,0 ;print counters at top
mov dx,offset gen_mes
call print ;print ifo messages
;
cld ;work up (sting ops)
;
play_loop: mov ah,1 ;pressing key interrupts play
int 16h
jz cont ;if key pressed,stop
stopplay: ret
cont: call print_data ;print gen and pop
cmp population,0 ;if no living cells,exit game
je stopplay
;
mov cx,2000 ;move matrix 2 to 1
lea si,ds:matrix_2
lea di,es:matrix_1
rep movs matrix_1,matrix_2
;
clear matrix_2
;
mov row_pos,1 ;start with row 1
loop1: mov col_pos,1 ; and column 1
loop2: peek matrix_1,col_pos,row_pos
call look_around
cmp al,cell ;check for cell (peek op)
jne nocell ;jump if no cell
cmp cl,2 ;cell survives if surrounded by
je survive ;2 or 3 other cells
cmp cl,3
je survive
locate row_byte,col_byte ;set cursor pos
output space,normal ;kill on screen
place matrix_2,col_pos,row_pos,space ;kill in matrix
dec population
jmp next
;
survive: place matrix_2,col_pos,row_pos,cell ;put in matrix
jmp next
;
nocell: cmp cl,3 ;give birth of new cell
jne next
inc population
locate row_byte,col_byte
output cell,normal ;make it bright
place matrix_2,col_pos,row_pos,cell ;put in matrix
;
next: inc col_pos ;do next column
cmp col_pos,79
jnb skip1 ;conditional jump too far
jmp loop2
skip1: inc row_pos ;do next row
cmp row_pos,23 ;done all?
jnb skip2 ;short jump problem again
jmp loop1
skip2: inc generation
jmp play_loop
play endp
;
;Look_Around checks to see how many cells are around a
;space. Only BX,CX,DI,SI are used.
;
look_around proc near
mov bx,row_pos ;find row
shl bx,1 ;get address from table of 80s
mov bx,row_addr[bx]
add bx,col_pos ;add column to it
add bx,offset matrix_1 ;add offset into data seg
mov di,14 ;set DI to last dir offset
mov cl,8 ;set CL to all cells
look_loop: mov si,direction[di] ;get direction offset
cmp byte ptr [bx][si],cell ;see if cell
je look_next
dec cl ;if not cell,reduce CL by 1
look_next: sub di,2 ;get next direction offset
jns look_loop ;done them all?
ret ;return to caller
look_around endp
;
;print_data outputs the population and the generation.
;Consider all registers lost;
;
print_data proc near
locate 0,11
mov ax,generation
call decimal_out
locate 0,30
mov ax,population
call decimal_out
ret
print_data endp
;
;Output a hex word in decimal.
;AX,DX,BP destroyed.
;
decout proc near
tens dw 1,10,100,1000,10000
leading_zero db 0 ;leading zero flag
;
decimal_out: mov leading_zero,1
mov bp,8 ;set BP to end of ten table
;
decout1: mov dx,0 ;prepare to divide
div tens[bp] ;divide by power of ten
add al,'0' ;convert to ascii
push dx ;store remainder
cmp al,'0' ;is byte a zero
jne send_char ;no, so print it
cmp bp,0 ;Is it last character?
je send_char ;yes, so print it
cmp leading_zero,1 ;Is it a leading zero?
je send_space ;yes, so don't print it
send_char: mov leading_zero,0
call chrout ;print it
jmp next_digit
send_space: mov al,' ' ;pad with spaces
call chrout
next_digit: pop ax ;get remainder back
sub bp,2 ;point to next lower ten
jns decout1 ;if still in table, do again
ret
decout endp
;
chrout proc near
mov ah,14 ;function call to output
int video ;print character
ret
chrout endp
;
routines proc near ;misc routines
;
;Print message pointed to by DS:DX
;
print: push ax
mov ah,9 ;set function call 9
int DOS_func ;print the message
pop ax
ret
;
;wait for key to be pressed
;
press_key: mov ah,0ch ;function 0ch (clear buffer)
mov al,7 ;set to no echo, wait for key
int DOS_func ;execute
ret
;
;clear the screen
;
cls: mov ah,0 ;set 80x25 (clears page)
mov al,2
int video
mov ah,5 ;select page zero
mov al,0
int video
ret ;return to caller
;
routines endp
code ends
end
video
mov ah,5 ;select page zero
mov al,0